﻿#region Copyright(C) 2013 FI Ltd. All rights reserved.

// ==================================================================================================
// Copyright(C) 2009 FI Ltd. All rights reserved.
//
// SYSTEM NAME	:   FI.Net Application Framework
// COMPONENT ID :   FI.ExceptionHandling
// COMPONENT DESC:  
//
// CREATED DATE/BY:  18 Aug 2018 / Tian Mi 
//
// REVISION HISTORY:	
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================

#endregion

using FI.Core.IoC;
using FI.Core.Utilities;
using System;
using System.Reflection;

namespace FI.Core.ExceptionHandling
{
    /// <summary>
    /// The custom <see cref="EventHandlerWrapper"/> used to wrap the <see cref="EventHandler"/> and make the exception thrown can be handled.
    /// </summary>
    public class ExceptionEventHandlerWrapper : EventHandlerWrapper
    {
        #region Properties
        /// <summary>
        /// Gets the name of the exception policy.
        /// </summary>
        /// <value>
        /// The name of the exception policy.
        /// </value>
        public string ExceptionPolicyName { get; private set; }
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="ExceptionEventHandlerWrapper"/> class.
        /// </summary>
        /// <param name="eventHandler">The event handler.</param>
        /// <param name="exceptionPolicyName">Name of the exception policy.</param>
        public ExceptionEventHandlerWrapper(Delegate eventHandler, string exceptionPolicyName)
            : base(eventHandler, GetWrapper(exceptionPolicyName))
        {
            this.ExceptionPolicyName = exceptionPolicyName;
        }
        #endregion

        #region Private Methods
        private static Action<Action> GetWrapper(string policyName)
        {
            Guard.ArgumentNotNullOrEmpty(policyName, "exceptionPolicyName");
            IExceptionHandler exceptionHandler = ServiceLocatorFactory.GetServiceLocator().GetService<IExceptionHandler>();

            return action =>
                 {
                     try
                     {
                         action();
                     }
                     catch (TargetInvocationException ex)
                     {
                         Exception exceptionToThrow;
                         if (null != ex.InnerException)
                         {
                             
                             if (exceptionHandler.HandleException(ex.InnerException, policyName, out exceptionToThrow))
                             {
                                 throw exceptionToThrow;
                             }
                         }
                         else
                         {
                             if (exceptionHandler.HandleException(ex, policyName, out exceptionToThrow))
                             {
                                 throw exceptionToThrow;
                             }
                         }
                     }
                     catch (Exception ex)
                     {
                         Exception exceptionToThrow;
                         if (exceptionHandler.HandleException(ex, policyName, out exceptionToThrow))
                         {
                             throw exceptionToThrow;
                         }
                     }
                 };
        }
        #endregion
    }
}
